using System;

namespace TimeSheetBLL
{
    /// <summary>
    /// A nice description of Utils goes here.
    /// 
    /// Version: $Id: Utils.cs,v 1.2 2004/05/18 15:33:20 jperrin Exp $
    /// 
    /// Date: 
    /// Copyright: 2004, Kanga Communications, Calgary, Alberta, Canada. 
    /// </summary>
    public class Utils
    {
        public Utils()
        {
        }

        #region Methods

        public static double GetExpectedHoursByDateRange(
            DateTime start, DateTime end, double hoursInDay)
        {
            double hours = 0;
            while (start <= end)
            {
                if (start.DayOfWeek != DayOfWeek.Saturday &&
                    start.DayOfWeek != DayOfWeek.Sunday)
                {
                    hours += hoursInDay;
                }
                start = start.AddDays(1);
            }
            return hours;
        }

        public static DateTime GetPreviousWeekEnd(DateTime date)
        {
            switch (date.DayOfWeek)
            {
                case DayOfWeek.Monday:
                    return date.AddDays(-3);
                case DayOfWeek.Tuesday:
                    return date.AddDays(-4);
                case DayOfWeek.Wednesday:
                    return date.AddDays(-5);
                case DayOfWeek.Thursday:
                    return date.AddDays(-6);
                case DayOfWeek.Friday:
                    return date;
                case DayOfWeek.Saturday:
                    return date.AddDays(-1);
                case DayOfWeek.Sunday:
                    return date.AddDays(-2);
                default:
                    throw new Exception(
                        "You somehow found a day that doesn't exist. Interesting.");
            }
        }

        public static DateTime GetPreviousWeekStart(DateTime date)
        {
            switch (date.DayOfWeek)
            {
                case DayOfWeek.Monday:
                    return date.AddDays(-9);
                case DayOfWeek.Tuesday:
                    return date.AddDays(-10);
                case DayOfWeek.Wednesday:
                    return date.AddDays(-11);
                case DayOfWeek.Thursday:
                    return date.AddDays(-12);
                case DayOfWeek.Friday:
                    return date.AddDays(-6);
                case DayOfWeek.Saturday:
                    return date.AddDays(-7);
                case DayOfWeek.Sunday:
                    return date.AddDays(-8);
                default:
                    throw new Exception(
                        "You somehow found a day that doesn't exist. Interesting.");
            }
        }

        public static DateTime GetPayPeriodStart(DateTime date)
        {
            if (date.Day > 15)
            {
                return new DateTime(date.Year, date.Month, 16);
            }
            else
            {
                return new DateTime(date.Year, date.Month, 1);
            }
        }

        public static DateTime GetPayPeriodEnd(DateTime date)
        {
            if (date.Day > 15)
            {
                return
                    new DateTime(
                        date.Year, date.Month, GetLastDayOfMonth(date.Month, date.Year));
            }
            else
            {
                return new DateTime(date.Year, date.Month, 15);
            }
        }

        public static DateTime GetMonthStart(DateTime date)
        {
            return new DateTime(date.Year, date.Month, 1);
        }

        public static DateTime GetMonthEnd(DateTime date)
        {
            return
                new DateTime(
                    date.Year, date.Month, GetLastDayOfMonth(date.Month, date.Year));
        }

        /// <summary>
        /// This method was stolen from Mono: mcs/class/corlib/System.Globalization CalendricalCalculations.cs
        /// Returns the last day of the month given a  month and a year;
        /// </summary>
        /// <param name="month"></param>
        /// <param name="year"></param>
        /// <returns></returns>
        private static int GetLastDayOfMonth(int month, int year)
        {
            if (month < 1 ||
                month > 12)
                throw new ArgumentOutOfRangeException(
                    "month",
                    "Month should be between One and Twelve.");
            switch (month)
            {
                case 1:
                    return 31;
                case 2:
                    if (!is_leap_year(year))
                        return 28;
                    else
                        return 29;
                    break;
                case 3:
                    return 31;
                case 5:
                    return 31;
                case 7:
                    return 31;
                case 8:
                    return 31;
                case 10:
                    return 31;
                case 12:
                    return 31;
            }
            return 30;
        }

        /// <summary>
        /// Given a year, returns whether it's a leap or not
        /// </summary>
        /// <param name="year"></param>
        /// <returns></returns>
        private static bool is_leap_year(int year)
        {
            return mod(14 + 11*year, 30) < 11;
        }

        private static double mod(double x, double y)
        {
            return x - y*Math.Floor(x/y);
        }

        #endregion
    }
}